package com.xxl.job.executor.util;

import com.xxl.job.core.context.XxlJobHelper;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CrontabUtil {

    public static List<CronTask> getCrontabTasks() {
        List<CronTask> tasks = new ArrayList<>();
        try {
            ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", "crontab -l");
            Process process = builder.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;

            while ((line = reader.readLine()) != null) {
                // 保留原始格式，不进行 trim()
                if (!line.isEmpty() && isValidCronTask(line)) {
                    CronTask task = parseCronTask(line);
                    if (task != null) {
                        tasks.add(task);
                        System.out.println("获取到的定时任务: schedule: " + task.getSchedule() + " command: " + task.getCommand());
                    }
                }
            }
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tasks;
    }

    /**
     * 禁用任务：根据任务命令找到任务，并将该任务在crontab中注释掉
     * @param command 任务的命令
     * @throws IOException
     */
    public static boolean disableCronTask(String schedule, String command) throws IOException {
        // 读取并备份当前 crontab 文件的内容
        List<String> originalLines = getCrontabFile();
        boolean taskFound = false;

        // 创建新的 crontab 文件内容
        List<String> modifiedCronLines = new ArrayList<>();

        for (String line : originalLines) {
            if (!line.isEmpty() && isValidCronTask(line)) {
                CronTask task = parseCronTask(line);
                if (task != null && task.getSchedule().equals(schedule) && task.getCommand().equals(command)) {
                    modifiedCronLines.add("#" + line);
                    taskFound = true;
                    System.out.println("获取到的定时任务: schedule: #" + task.getSchedule() + " command: " + task.getCommand());
                    continue;
                }
            }
            // 如果不匹配，保留原始行
            modifiedCronLines.add(line);
        }
        // 如果找到匹配的任务，则写入修改后的 crontab
        if (taskFound) {
            writeCrontab(modifiedCronLines);
        }

        return taskFound;
    }
    //启用定时任务
    public static boolean enableCronTask(String schedule,String command) throws IOException {
        // 读取并备份当前 crontab 文件的内容
        List<String> originalLines = getCrontabFile();
        boolean taskFound = false;

        // 创建新的 crontab 文件内容
        List<String> modifiedCronLines = new ArrayList<>();

        for (String line : originalLines) {
            // 检查是否为有效的定时任务行
            if (!line.isEmpty() && isValidCronTask(line)) {
                CronTask task = parseCronTask(line);
                if (task != null && task.getSchedule().equals(schedule) && task.getCommand().equals(command)) {
                    line=task.getSchedule().replaceFirst("#","") + " " +task.getCommand();
                    modifiedCronLines.add(line);
                    taskFound = true;
                    System.out.println("获取到的定时任务: schedule: #" + task.getSchedule() + " command: " + task.getCommand());
                    continue;
                }
            }
            // 如果不匹配，保留原始行
            modifiedCronLines.add(line);
        }
        // 如果找到匹配的任务，则写入修改后的 crontab
        if (taskFound) {
            writeCrontab(modifiedCronLines);
        }

        return taskFound;
    }

    //编辑修改定时任务
    public static boolean UpdateCronTask(String schedule,String newSchedule,String command,String newCommand) throws IOException {
        // 读取并备份当前 crontab 文件的内容
        List<String> originalLines = getCrontabFile();
        boolean taskFound = false;

        // 创建新的 crontab 文件内容
        List<String> modifiedCronLines = new ArrayList<>();

        for (String line : originalLines) {
            // 检查是否为有效的定时任务行
            if (!line.isEmpty() && isValidCronTask(line)) {
                CronTask task = parseCronTask(line);
                System.out.println("原命令" + task.getSchedule() + " " + task.getCommand());
                System.out.println("新命令" + newSchedule + " " + newCommand);
                if (task != null && task.getSchedule().equals(schedule) && task.getCommand().equals(command)) {
                    // 修改
                    line=newSchedule + " " + newCommand;
                    modifiedCronLines.add(line);
                    taskFound = true;
                    continue;
                }
            }
            // 如果不匹配，保留原始行
            modifiedCronLines.add(line);
        }
        // 如果找到匹配的任务，则写入修改后的 crontab
        if (taskFound) {
            writeCrontab(modifiedCronLines);
        }

        return taskFound;
    }

    // 新增定时任务
    public static boolean addCronTask(String schedule, String command) throws IOException {
        // 读取并备份当前 crontab 文件的内容
        List<String> originalLines = getCrontabFile();

        // 创建新的 crontab 文件内容
        List<String> modifiedCronLines = new ArrayList<>();

        for (String line : originalLines) {
            //保留原始行
            modifiedCronLines.add(line);
        }
        modifiedCronLines.add(schedule + " " + command);

        writeCrontab(modifiedCronLines);


        return true;
    }

    /**
     * 判断字符串是否为有效的定时任务格式
     */
    private static boolean isValidCronTask(String line) {
        // 定义符合标准 crontab 格式的正则表达式，只判断 schedule 部分
        String cronRegex = "^(#?\\s*(?:@\\w+|([\\d\\*/,-]+\\s+){5})).*$";
        return line.matches(cronRegex);
    }

    /**
     * 分解定时任务
     */
    private static CronTask parseCronTask(String line) {
        // 正则表达式匹配 cron 调度部分（包含5个时间字段或特殊的 @ 表达式）
        String cronRegex = "^(#?\\s*(?:@\\w+|([\\d\\*/,-]+\\s+){5}))";
        Pattern pattern = Pattern.compile(cronRegex);
        Matcher matcher = pattern.matcher(line);

        if (matcher.find()) {
            String schedule = matcher.group().trim(); // 匹配到的调度部分
            String command = line.substring(matcher.end()).trim(); // 调度部分后的内容为命令
            return new CronTask(schedule, command);
        }

        // 如果没有匹配到有效的调度部分，则返回 null
        return null;
    }



    // 内部类定义定时任务
    public static class CronTask {
        private String schedule;
        private String command;

        public CronTask(String schedule, String command) {
            this.schedule = schedule;
            this.command = command;
        }

        public String getSchedule() {
            return schedule;
        }

        public String getCommand() {
            return command;
        }
    }

    /**
     * 获取当前用户的 crontab 文件内容，作为备份。
     */
    public static List<String> getCrontabFile() throws IOException {
        List<String> lines = new ArrayList<>();
        ProcessBuilder builder = new ProcessBuilder("/bin/sh", "-c", "crontab -l");
        Process process = builder.start();

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
             BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {

            // 读取标准输出
            String line;
            while ((line = reader.readLine()) != null) {
                lines.add(line);
            }

            // 读取错误输出
            String errorLine;
            while ((errorLine = errorReader.readLine()) != null) {
                System.err.println("错误信息: " + errorLine);
            }

            int exitCode = process.waitFor();
            if (exitCode != 0) {
                System.err.println("crontab -l 命令执行失败，退出代码: " + exitCode);
            } else {
                System.out.println("备份函数被调用");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("命令执行被中断", e);
        }

        return lines;
    }


    /**
     * 写入修改后的 crontab 文件
     */
    private static void writeCrontab(List<String> cronLines) throws IOException {
        // 将修改后的 crontab 内容写入临时文件
        File tempFile = File.createTempFile("crontab", ".txt");
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) {
            for (String line : cronLines) {
                writer.write(line);
                writer.newLine();
            }
        }

        // 使用 crontab - 重新设置 crontab
        ProcessBuilder builder = new ProcessBuilder("crontab", tempFile.getAbsolutePath());
        Process process = builder.start();

        // 捕获命令的输出和错误流
        try (BufferedReader outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
             BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {

            // 读取标准输出
            String outputLine;
            while ((outputLine = outputReader.readLine()) != null) {
                XxlJobHelper.log("crontab 输出: " + outputLine);
            }

            // 读取错误输出
            String errorLine;
            while ((errorLine = errorReader.readLine()) != null) {
                System.err.println("crontab 错误: " + errorLine);
            }

            int exitCode = process.waitFor();
            if (exitCode == 0) {
                XxlJobHelper.log("crontab 文件更新成功");
            } else {
                XxlJobHelper.log("crontab 文件更新失败，退出代码: " + exitCode);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("命令执行被中断", e);
        } finally {
            // 删除临时文件
            if (tempFile.exists()) {
                boolean deleted = tempFile.delete();
                if (!deleted) {
                    XxlJobHelper.log("删除临时文件失败: " + tempFile.getAbsolutePath());
                }
            }
        }
    }

}
